package com.jiangruan.javainspect.address;

import com.jiangruan.javainspect.utils.Base58;
import com.jiangruan.javainspect.utils.Hash;

import java.security.*;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECPoint;
import java.util.Arrays;

/**
 * @author:liyaqi
 * @email:3441520483@qq.com
 * @desc:该类用于生成比特币的地址
 * @datatime: 2021/12/20 10:47
 */
public class Address {
    /**
     * java中原生，生成一对秘钥，并将密钥对，对象KeyPair返回
     * @return 生成的密钥对
     */
    public KeyPair generateKeys(){
        try {
            KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
            //secp256k1,secp256r1
            ECGenParameterSpec spec = new ECGenParameterSpec("secp256k1");
            generator.initialize(spec);
            return generator.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据提供的密钥对数据，推导生成一个原始格式的比特币地址，并返回
     * @param keyPair 提供的密钥对信息
     * @return 推导生成的比特币地址
     */
    public String newAddress(KeyPair keyPair){
        if (keyPair == null){
            return null;
        }
        ECPublicKey publickKey = (ECPublicKey) keyPair.getPublic();
        ECPoint point = publickKey.getW();
        byte[] xBytes = point.getAffineX().toByteArray();
        byte[] yBytes = point.getAffineY().toByteArray();
        byte[] pubKey = toUncompresssPubKey(xBytes,yBytes);

        byte[] sha256 = Hash.SHA256(pubKey);
        //公钥哈希
        byte[] pubHash = Hash.RIPEMD160(sha256);
        //添加前缀
        byte[] version = new byte[1];
        version[0] = 0x00;
        byte[] ver_pubhash = new byte[version.length + pubHash.length];
        System.arraycopy(version,0,ver_pubhash,0,version.length);
        System.arraycopy(pubHash,0,ver_pubhash,1,pubHash.length);

        //双哈希，取校验位
        byte[] hash1 = Hash.SHA256(ver_pubhash);
        byte[] hash2 = Hash.SHA256(hash1);
        byte[] check = new byte[4];
        System.arraycopy(hash2,0,check,0,4);

        byte[] ver_pubhash_check = new byte[ver_pubhash.length + check.length];
        System.arraycopy(ver_pubhash,0,ver_pubhash_check,0,ver_pubhash.length);
        System.arraycopy(check,0,ver_pubhash_check,ver_pubhash.length,check.length);

        //base58编码
        String addre = Base58.encode(ver_pubhash_check);
        System.out.println(addre);
        return addre;
    }

    /**
     * 该方法根据X坐标和Y坐标数据，用于拼接原始格式的公钥
     * @param x X坐标数据
     * @param y Y坐标数据
     * @return 原始格式的公钥
     */
    private static byte[] toUncompresssPubKey(byte[] x,byte[] y){
        //原始格式公钥：04 + X坐标（32字节） + Y坐标（32字节）
        byte[] publicKey = new byte[65];
        publicKey[0] = 04;
        if (x.length == 32){
            //将X坐标全部拷贝到创建的原始格式公钥去
            System.arraycopy(x,0,publicKey,1,x.length);
        } else if (x.length > 32){
            System.arraycopy(x,1,publicKey,1,32);
        }
        if (y.length == 32){
            System.arraycopy(y,0,publicKey,3,y.length);
        } else if (y.length > 32) {
            System.arraycopy(y,1,publicKey,33,32);
        }
        return publicKey;
    }
    //校验比特币地址
    public  boolean verifyAddress(String address){
        //进行Base58解码
        //System.out.println(address);
        byte[] decode = Base58.decode(address);
        byte[] check=new byte[4];
        System.arraycopy(decode,decode.length-check.length,check,0,check.length);
        byte[] Ver_pub=new byte[decode.length-check.length];
        System.arraycopy(decode,0,Ver_pub,0,Ver_pub.length);
        //双hash，取前四个字节
        byte[] hash1 = Hash.SHA256(Ver_pub);
        byte[] hash2 = Hash.SHA256(hash1);
        byte[] verifyCheck =new byte[4];
        System.arraycopy(hash2,0,verifyCheck,0,verifyCheck.length);
        System.out.println(check[0]);
        //System.out.println(verifyCheck[0]);
        //比较两个字节数组是否相等
        boolean equals = Arrays.equals(check, verifyCheck);
        return equals;
    }
}
